import re, zipfile

from zipfile import ZipFile
from chardet.universaldetector import UniversalDetector

class LogParser(ZipFile):

    @property
    def zip_files_list(self):
        return list(
            f for f in self.namelist() if f.split('.')[-1] == 'zip' and not f.startswith('__MACOSX/')
        )

    @property
    def names_list(self):
        return self.namelist()
    
    def __init_subclass__(self, filename: str) -> None:
        self.filename = filename
        return super().__init_subclass__(file=self.filename, mode='r')

    @staticmethod
    def detect_encoding(line):
        if isinstance(line, bytes):
            detector = UniversalDetector()
            detector.reset()
            detector.feed(line)
            detector.close()
            return detector.result['encoding']
        elif isinstance(line, zipfile.ZipExtFile):
            detector = UniversalDetector()
            detector.reset()
            for l in line:
                detector.feed(l)
                if detector.done: 
                    break
            detector.close()
            return detector.result['encoding']
        else:
            return 'ascii'
    
    @property
    def infoToDf(self):
        pattern_info = re.compile(r'.?information.txt')
        if list(filter(pattern_info.match, self.names_list)):
            info_name = list(filter(pattern_info.match, self.names_list))[0]
            country, ip, username = tuple(None for _ in range(3))
            with self.open(info_name) as info_file:
                codepage = self.detect_encoding(info_file)
                info_file.seek(0)
                for line in info_file:
                    if not line.rstrip():
                        continue
                    if line.startswith(b'Country: '):
                        try:
                            country = line.rsplit(b': ')[-1].decode(codepage).strip()
                        except:
                            country = str(line.rsplit(b': ')[-1].rstrip())
                    elif line.startswith(b'Ip: '):
                        try:
                            ip = line.rsplit(b': ')[-1].decode(codepage).strip()
                        except:
                            ip = str(line.rsplit(b': ')[-1].rstrip())
                    elif line.startswith(b'User Name: '):
                        try:
                            username = line.rsplit(b': ')[-1].decode(codepage).strip()
                        except:
                            username = str(line.rsplit(b': ')[-1].rstrip())
                    if all(map(lambda x: x != None, [country, ip, username])):
                        break
            df_info = {
                'files_list': self.names_list,
                'country': country,
                'ip': ip,
                'username': username,
            }
            return df_info
        return None

    @property  
    def psswrdToDf(self):
        pattern_passwords = re.compile(r'.?passwords.txt')
        if list(filter(pattern_passwords.match, self.names_list)):
            df_info = []
            password_name = list(filter(pattern_passwords.match, self.names_list))[0]
            soft, host, login, password = tuple(None for _ in range(4))
            with self.open(password_name) as passwords_file:
                codepage = self.detect_encoding(passwords_file)
                codepage = codepage if codepage else 'ascii'
                passwords_file.seek(0)
                for line in passwords_file.readlines():
                    if not line.rstrip():
                        soft, host, login, password = tuple(None for _ in range(4))
                        continue
                    if line.startswith(b'Soft: '):
                        try:
                            soft = line.rsplit(b': ')[-1].decode(codepage).strip()
                        except:
                            soft = str(line.rsplit(b': ')[-1].rstrip())
                    elif line.startswith(b'Host: '):
                        try:
                            host = line.rsplit(b': ')[-1].decode(codepage).strip()
                        except:
                            host = str(line.rsplit(b': ')[-1].rstrip())
                    elif line.startswith(b'Login: '):
                        try:
                            login = line.rsplit(b': ')[-1].decode(codepage).strip()
                        except:
                            login = str(line.rsplit(b': ')[-1].rstrip())
                    elif line.startswith(b'Password: '):
                        try:
                            password = line.rsplit(b': ')[-1].decode(codepage).strip()
                        except:
                            password = str(line.rsplit(b': ')[-1].rstrip())
                    if all(map(lambda x: x != None, [soft, host, login, password])):
                        df_info.append(
                            {
                                'soft': soft,
                                'host': host,
                                'login': login,
                                'password': password,
                            }
                        )
                        soft, host, login, password = tuple(None for _ in range(4))
            return df_info
        return None
